#include "PropertyValue.h"
#include "Common/Exceptions/ProductException.h"

using namespace cmn;

namespace editor_core {

	PropertyValue::PropertyValue( PropertyValueType type, Union value ) :
		m_type( type ),
		m_union( value )
	{}

	PropertyValue::PropertyValue( PropertyValueType type, std::string value ) :
		m_type( type ),
		m_string( value )
	{}

	PropertyValue::PropertyValue( const PropertyValue& other ) :
		m_type( other.m_type ),
		m_union( other.m_union ),
		m_string( other.m_string )
	{}

	PropertyValue::PropertyValue( bool value ) : m_type( PropertyValueType::Bool ) { m_union.m_bool = value; }
	PropertyValue::PropertyValue( int value ) : m_type( PropertyValueType::Int ) { m_union.m_int = value; }
	PropertyValue::PropertyValue( float value ) : m_type( PropertyValueType::Float ) { m_union.m_float = value; }

	PropertyValue& PropertyValue::operator=( const PropertyValue& other ) {
		if( this == &other ) return *this; // handle self assignment

		m_type = other.m_type;
		m_union = other.m_union;
		m_string = other.m_string;

		return *this;
	}

	PropertyValue PropertyValue::CreateBoolValue( bool value ) {
		Union u;
		u.m_bool = value;
		return PropertyValue( PropertyValueType::Bool, u );
	}

	PropertyValue PropertyValue::CreateIntValue( int value ) {
		Union u;
		u.m_int = value;
		return PropertyValue( PropertyValueType::Int, u );
	}

	PropertyValue PropertyValue::CreateFloatValue( float value ) {
		Union u;
		u.m_float = value;
		return PropertyValue( PropertyValueType::Float, u );
	}

	PropertyValue PropertyValue::CreateStringValue( std::string value ) {
		return PropertyValue( PropertyValueType::String, value );
	}

	PropertyValue PropertyValue::CreateFileValue( std::string value ) {
		return PropertyValue( PropertyValueType::File, value );
	}

	bool PropertyValue::GetBool() const {
		if( m_type != PropertyValueType::Bool ) throw ProductException( "Wrong type" );
		return m_union.m_bool;
	}

	void PropertyValue::SetBool( bool value ) {
		if( m_type != PropertyValueType::Bool ) throw ProductException( "Wrong type" );
		m_union.m_bool = value;
	}

	int PropertyValue::GetInt() const {
		if( m_type != PropertyValueType::Int ) throw ProductException( "Wrong type" );
		return m_union.m_int;
	}

	void PropertyValue::SetInt( int value ) {
		if( m_type != PropertyValueType::Int ) throw ProductException( "Wrong type" );
		m_union.m_int = value;
	}

	float PropertyValue::GetFloat() const {
		if( m_type != PropertyValueType::Float ) throw ProductException( "Wrong type" );
		return m_union.m_float;
	}

	void PropertyValue::SetFloat( float value ) {
		if( m_type != PropertyValueType::Float ) throw ProductException( "Wrong type" );
		m_union.m_float = value;
	}

	std::string PropertyValue::GetString() const {
		if( m_type != PropertyValueType::String ) throw ProductException( "Wrong type" );
		return m_string;
	}

	void PropertyValue::SetString( std::string value ) {
		if( m_type != PropertyValueType::String ) throw ProductException( "Wrong type" );
		m_string = value;
	}

	std::string PropertyValue::GetFile() const {
		if( m_type != PropertyValueType::File ) throw ProductException( "Wrong type" );
		return m_string;
	}

	void PropertyValue::SetFile( std::string value ) {
		if( m_type != PropertyValueType::File ) throw ProductException( "Wrong type" );
		m_string = value;
	}

	bool operator== ( const PropertyValue& a, const PropertyValue& b ) {
		if( a.GetType() != b.GetType() ) return false;
		PropertyValueType type = a.GetType();
		switch( type ) {
			case PropertyValueType::Bool:
				return a.GetBool() == b.GetBool();
			case PropertyValueType::Int:
				return a.GetInt() == b.GetInt();
			case PropertyValueType::Float:
				return a.GetFloat() == b.GetFloat();
			case PropertyValueType::String:
				return a.GetString() == b.GetString();
			case PropertyValueType::File:
				return a.GetFile() == b.GetFile();
			default:
				return false;
		}
	}

	bool operator!= ( const PropertyValue& a, const PropertyValue& b ) {
		if( a.GetType() != b.GetType() ) return true;
		PropertyValueType type = a.GetType();
		switch( type ) {
			case PropertyValueType::Bool:
				return a.GetBool() != b.GetBool();
			case PropertyValueType::Int:
				return a.GetInt() != b.GetInt();
			case PropertyValueType::Float:
				return a.GetFloat() != b.GetFloat();
			case PropertyValueType::String:
				return a.GetString() != b.GetString();
			case PropertyValueType::File:
				return a.GetFile() != b.GetFile();
			default:
				return false;
		}
	}

}
